package edu.dali.enterprise_test.kits;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelTemplate {
	private static ExcelTemplate et = new ExcelTemplate();
	
	private final static String STYLE = "#style";
	private final static String DEFAULTSTYLE = "#defaultStyle";
	
	private Workbook wb;
	private int initColumnIndex;
	private int initRowIndex;
	private int currentColumnIndex;
	private int currentRowIndex;
	private Sheet sheet;
	private Row currentRow;
	private int lastRowNum;
	private Map<Integer , CellStyle> styles;

	private CellStyle defaultStyle;
	
	private ExcelTemplate(){
	}
	
	public static ExcelTemplate getInstants() {
		return et;
	}
	
	/**
	 * 根据classpath 读取excel模板文件
	 * @param path
	 */
	public ExcelTemplate readTemplateByClassPath(String path) {
		try {
//			InputStream is = this.getClass().getResourceAsStream(path);
//			wb = WorkbookFactory.create(is);
			wb = WorkbookFactory.create(ExcelTemplate.class.getClassLoader().getResourceAsStream(path));
			initTemplate();
		} catch (InvalidFormatException e) {
			e.printStackTrace();
			throw new RuntimeException("读入模板格式有误!");
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("读入模板不存在!");
		}
		return this;
	}
	
	
	/**
	 * 根据路径 读取excel模板文件
	 * @param path
	 */
	public ExcelTemplate readTemplateByPath(String path) {
		try {
			wb = WorkbookFactory.create(new File(path));
			initTemplate();
		} catch (InvalidFormatException e) {
			e.printStackTrace();
			throw new RuntimeException("读入模板格式有误!");
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("读入模板不存在!");
		}
		return this;
	}
	
	/**
	 * 生成excel 写入到文件
	 * @param pathname
	 */
	public void writeToFile(String pathname) {
		FileOutputStream fos = null;
		
		try {
			fos = new FileOutputStream(pathname);
			wb.write(fos);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException("文件不存在!");
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("文件被占用!");
		} finally {
			try {
				if(fos != null) fos.close();
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException("文件不存在!");
			}
		}
	}
	
	/**
	 * 生成excel 写入流中
	 * @param os
	 */
	public void writeToStream(OutputStream os) {
		try {
			wb.write(os);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("文件流被占用!");
		} finally {
			try {
				if(os != null) os.close();
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException("文件流不存在!");
			}
		}
	}
	
	/**
	 * 初始化模板
	 */
	public void initTemplate() {
		sheet = wb.getSheetAt(0);
		initConfigData();
		lastRowNum = sheet.getLastRowNum();
		createNewRow();
	}

	/**
	 * 初始化数据
	 */
	private void initConfigData() {
		boolean findData = false;
		for(Row row : sheet) {
			if(findData) break;
			for(Cell cell : row) {
				if(cell.getCellType() != Cell.CELL_TYPE_STRING) continue;
				
				String str = cell.getStringCellValue().trim();
				if(str.equals("#data")) {
					initColumnIndex = cell.getColumnIndex();
					initRowIndex = cell.getRowIndex();
					currentColumnIndex = initColumnIndex;
					currentRowIndex = initRowIndex;
					findData = true;
					initStyle();
					
					break;
				}
				
			}
		}

	}
	
	/**
	 * 创建样式
	 */
	private void initStyle() {
		styles = new HashMap<Integer, CellStyle>();
		for(Row row : sheet) {
			for(Cell cell : row) {

				CellStyle cstyle = cell.getCellStyle();
				int ctype = cell.getCellType();
				if(cell.getCellType() != Cell.CELL_TYPE_STRING && cell.getCellType() != Cell.CELL_TYPE_NUMERIC) continue;
				String str = "";
				if (cell.getCellType() == Cell.CELL_TYPE_STRING) str = cell.getStringCellValue().trim();
				if(cstyle != null && !str.equals(DEFAULTSTYLE)) {
					styles.put(cell.getColumnIndex(), cell.getCellStyle());
				} else if(str.equals(DEFAULTSTYLE)) {
					defaultStyle = cell.getCellStyle();
				}
				
			}
		}
		
		
	}

	/**
	 * 填写单元格
	 * @param value
	 */
	public void createCell(Object value) {
		Cell cell = currentRow.createCell(currentColumnIndex);
		if(styles.containsKey(currentColumnIndex)) {
			cell.setCellStyle(styles.get(currentColumnIndex));
		} else {
			cell.setCellStyle(defaultStyle);
		}
		if (value instanceof Double){
			cell.setCellValue((Double.valueOf(value.toString())));
		} else {
			if (value != null)
				cell.setCellValue(value.toString());
			else
				cell.setCellValue("");
		}

		currentColumnIndex++;
	}
	
	/**
	 * 添加一行
	 */
	public void createNewRow() {
		if(lastRowNum >currentRowIndex && currentRowIndex != initRowIndex ) {
			sheet.shiftRows(currentRowIndex, lastRowNum, 1, true, true);
			lastRowNum++;
		}
		currentRow = sheet.createRow(currentRowIndex);
		currentRowIndex++;
		currentColumnIndex = initColumnIndex;
	}
	
	/**
	 * 替换常量
	 * @param data
	 */
	public void replaceFinalData(Map<String , Object> data) {
		for(Row row : sheet) {
			for(Cell cell : row) {
				if(cell.getCellType() != Cell.CELL_TYPE_STRING ) continue;
				String str = cell.getStringCellValue().trim();
				if(str.contains("#")) {
					if(data.containsKey(str.substring(str.indexOf("#")+1 ))) {
						cell.setCellValue(str.substring(0, str.indexOf("#")) + (String) data.get(str.substring(str.indexOf("#")+1 )));
					}
				}
			}
			
		}
	}
	
	/**
	 * 遍历填入数据
	 * @param map
	 */
	@SuppressWarnings("unchecked")
	public ByteArrayOutputStream dataIterator(Map<String , Object> map) {
		List<List<Object>> data = (List<List<Object>>) map.get("data");

		if (data != null) {
			for(int i = 0 ; i < data.size() ; i++) {
				for(int j = 0 ; j < data.get(i).size() ; j++) {
					Object val = data.get(i).get(j);

					createCell(val);
//				if(j == 4 ) {
//					createCell(Double.parseDouble(val));
//				} else {
//					createCell(val);
//				}

				}
				if(i < data.size()-1 ) createNewRow();
			}
			map.remove("data");
		}

		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		this.replaceFinalData(map);
		this.writeToStream(bos);
		return bos;
	}
}
